﻿/*
 * masterdm.cpp
 *
 *  Created on: 2017年5月17日
 *      Author: work
 */

#include "masterdm.h"

#include <dm/os/log/logger.hpp>
#include <dm/scada/scada.hpp>
#include <dm/os/protocol/protocolslaver.hpp>
#include <dm/datetime.hpp>

static const char* logModule = "CMasterDm.dmsync.app";

/**
 * 构造函数
 */
CMasterDm::CMasterDm():dm::os::protocol::CProtocolMaster(){
	m_callStep = CSStatus;
	m_callIndex = 0;
	m_callInterval = 2;
	m_sendInterval = 0;

	m_ackCall = false;
	m_ackRmtCtl = true;
	m_ackParas = true;

	m_clockInterval = 0;
	m_acceptClock = false;

	m_offset_s = 0;
	m_offset_d = 0;
	m_offset_m = 0;
	m_offset_c = 0;
	m_offset_r = 0;
	m_offset_p = 0;
	m_offset_a = 0;

	m_size_s = -1;
	m_size_d = -1;
	m_size_m = -1;
	m_size_c = -1;
	m_size_r = -1;
	m_size_p = -1;
	m_size_a = -1;

	log().debug(THISMODULE "创建对象");
	setRefreshInterval(100);
}

CMasterDm::~CMasterDm(){
	log().debug(THISMODULE "销毁对象");
}

const char* CMasterDm::name()const{
	return "DM Master";
}

CMasterDm::frame_t& CMasterDm::getRxFrame(){
	return m_rxFrame;
}

const CMasterDm::frame_t& CMasterDm::getTxFrame(){
	return m_txFrame;
}

bool CMasterDm::setStatusOffset( int offset ){
	if( offset<0 || offset>sizeOfStatus() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfStatus());
		return false;
	}

	m_offset_s = offset;

	if( m_size_s<0 || (m_size_s+offset)>sizeOfStatus() )
		m_size_s = sizeOfStatus() - offset;

	return true;
}

bool CMasterDm::setStatusSize( int size ){
	if( size<0 || (size+m_offset_s)>sizeOfStatus() )
		m_size_s = sizeOfStatus() - m_offset_s;
	else
		m_size_s = size;

	log().debug(THISMODULE "设置数量%d",m_size_s);

	return true;
}

bool CMasterDm::setDiscreteOffset( int offset ){
	if( offset<0 || offset>sizeOfDiscrete() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfDiscrete());
		return false;
	}

	m_offset_d = offset;
	if( m_size_d<0 || (m_size_d+offset)>sizeOfDiscrete() )
		m_size_d = sizeOfDiscrete() - offset;

	return true;
}

bool CMasterDm::setDiscreteSize( int size ){
	if( size<0 || (size+m_offset_d)>sizeOfDiscrete() )
		m_size_d = sizeOfDiscrete() - m_offset_d;
	else
		m_size_d = size;

	log().debug(THISMODULE "设置数量%d",m_size_d);

	return true;
}

bool CMasterDm::setMeasureOffset( int offset ){
	if( offset<0 || offset>sizeOfMeasure() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfMeasure());
		return false;
	}

	m_offset_m = offset;
	if( m_size_m<0 || (m_size_m+offset)>sizeOfMeasure() )
		m_size_m = sizeOfMeasure() - offset;

	return true;
}

bool CMasterDm::setMeasureSize( int size ){
	if( size<0 || (size+m_offset_m)>sizeOfMeasure() )
		m_size_m = sizeOfMeasure() - m_offset_m;
	else
		m_size_m = size;

	log().debug(THISMODULE "设置数量%d",m_size_m);

	return true;
}

bool CMasterDm::setCumulantOffset( int offset ){
	if( offset<0 || offset>sizeOfCumulant() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfCumulant());
		return false;
	}

	m_offset_c = offset;
	if( m_size_c<0 || (m_size_c+offset)>sizeOfCumulant() )
		m_size_c = sizeOfCumulant() - offset;

	return true;
}

bool CMasterDm::setCumulantSize( int size ){
	if( size<0 || (size+m_offset_c)>sizeOfCumulant() )
		m_size_c = sizeOfCumulant() - m_offset_c;
	else
		m_size_c = size;

	log().debug(THISMODULE "设置数量%d",m_size_c);

	return true;
}

bool CMasterDm::setRmtctlOffset( int offset ){
	if( offset<0 || offset>sizeOfRmtctl() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfRmtctl());
		return false;
	}

	m_offset_r = offset;
	if( m_size_r<0 || (m_size_r+offset)>sizeOfRmtctl() )
		m_size_r = sizeOfRmtctl() - offset;

	return true;
}

bool CMasterDm::setRmtctlSize( int size ){
	if( size<0 || (size+m_offset_r)>sizeOfRmtctl() )
		m_size_r = sizeOfRmtctl() - m_offset_r;
	else
		m_size_r = size;

	log().debug(THISMODULE "设置数量%d",m_size_r);

	return true;
}

bool CMasterDm::setParameterOffset( int offset ){
	if( offset<0 || offset>sizeOfParameter() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfParameter());
		return false;
	}

	m_offset_p = offset;
	if( m_size_p<0 || (m_size_p+offset)>sizeOfParameter() )
		m_size_p = sizeOfParameter() - offset;

	return true;
}

bool CMasterDm::setParameterSize( int size ){
	if( size<0 || (size+m_offset_p)>sizeOfParameter() )
		m_size_p = sizeOfParameter() - m_offset_p;
	else
		m_size_p = size;

	log().debug(THISMODULE "设置数量%d",m_size_p);

	return true;
}

bool CMasterDm::setActionOffset( int offset ){
	if( offset<0 || offset>sizeOfAction() ){
		log().warnning(THISMODULE "无效偏移%d 总数%d",offset,sizeOfAction());
		return false;
	}

	m_offset_a = offset;
	if( m_size_a<0 || (m_size_a+offset)>sizeOfAction() )
		m_size_a = sizeOfAction() - offset;

	return true;
}

bool CMasterDm::setActionSize( int size ){
	if( size<0 || (size+m_offset_a)>sizeOfAction() )
		m_size_a = sizeOfAction() - m_offset_a;
	else
		m_size_a = size;

	log().debug(THISMODULE "设置数量%d",m_size_a);

	return true;
}

void CMasterDm::reset( const ts_t& ts,const rts_t& rts ){
	dm::os::protocol::CProtocolMaster::reset(ts,rts);
	enableRequestMsgCheck(true);
	enableAnswerMsgCheck(true);
	setTask_call(ts,rts,0,60);
}

CMasterDm::EAction CMasterDm::dealRxFrame( const ts_t& ts,const rts_t& rts ){
	noWait();

	enableRequestMsgCheck(true);
	enableAnswerMsgCheck(true);

	dm::uint32 start;
	dm::uint16 count;
	dm::os::msg::CMsgInfo msg;

	dm::CTimeStamp::s_t st;

	bool logged = false;

	switch( m_rxFrame.getFun() ){
	case CFrameDm::Fun_TestAck:
		return Action_Nothing;
		break;

	case CFrameDm::Fun_Status:
		if( m_rxFrame.getData_status(start,count) ){
			if( count>0 ){
				dm::scada::CStatus status;
				for( dm::uint16 i=0;i<count;++i ){
					if( m_rxFrame.getData_status(i,status) ){
						if( int(start+i)<m_offset_s || int(start+i)>=m_offset_s+m_size_s ){
							if( !logged ){
								log().info(THISMODULE "超出范围(%d,%d)的状态量%d",m_offset_s,m_size_s+m_offset_s,start+i);
								logged = true;
							}
							continue;
						}

						updateStatus( start+i,status);
					}else{
						log().warnning(THISMODULE "获取状态量信息失败%d",i);
						break;
					}
				}

				m_callIndex += count;
				log().debug(THISMODULE "召唤下一组状态量%d",m_callIndex);
			}else{
				if( m_callGroup==0 ){
					m_callStep = CSDiscrete;
					m_callIndex = m_offset_d;
					log().debug(THISMODULE "切换到召唤离散量");
				}else{
					log().debug(THISMODULE "召唤状态量完成");
					endTask_call(ts,rts,Success);
				}
			}
		}
		break;
	case CFrameDm::Fun_Discrete:
		if( m_rxFrame.getData_discrete(start,count) ){
			if( count>0 ){
				dm::scada::CDiscrete discrete;
				for( dm::uint16 i=0;i<count;++i ){
					if( m_rxFrame.getData_discrete(i,discrete) ){
						if( int(start+i)<m_offset_d || int(start+i)>=m_offset_d+m_size_d ){
							if( !logged ){
								log().info(THISMODULE "超出范围(%d,%d)的离散量%d",m_offset_d,m_size_d+m_offset_d,start+i);
								logged = true;
							}

							continue;
						}
						updateDiscrete( start+i,discrete);
					}else{
						log().warnning(THISMODULE "获取离散量信息失败%d",i);
						break;
					}

				}
				m_callIndex += count;
				log().debug(THISMODULE "召唤下一组离散量%d",m_callIndex);
			}else{
				if( m_callGroup==0 ){
					m_callStep = CSMeasure;
					m_callIndex = m_offset_m;
					log().debug(THISMODULE "切换到召唤测量量");
				}else{
					log().debug(THISMODULE "召唤离散量完成");
					endTask_call(ts,rts,Success);
				}
			}
		}
		break;
	case CFrameDm::Fun_Measure:
		if( m_rxFrame.getData_measure(start,count)){
			if( count>0 ){
				dm::scada::CMeasure measure;
				for( dm::uint16 i=0;i<count;++i ){
					if( m_rxFrame.getData_measure(i,measure) ){
						if( int(start+i)<m_offset_m || int(start+i)>=m_offset_m+m_size_m ){
							if( !logged ){
								log().info(THISMODULE "超出范围(%d,%d)的测量量%d",m_offset_m,m_size_m+m_offset_m,start+i);
								logged = true;
							}
							continue;
						}
						updateMeasure( start+i,measure.getValue());
					}else{
						log().warnning(THISMODULE "获取测量量信息失败%d",i);
						break;
					}

				}
				m_callIndex += count;
				log().debug(THISMODULE "召唤下一组测量量%d",m_callIndex);
			}else{
				if( m_callGroup==0 ){
					m_callStep = CSCumulant;
					m_callIndex = m_offset_c;
					log().debug(THISMODULE "切换到召唤累计量");
				}else{
					log().debug(THISMODULE "召唤测量量完成");
					endTask_call(ts,rts,Success);
				}
			}
		}
		break;
	case CFrameDm::Fun_Cumulant:
		if( m_rxFrame.getData_cumulant(start,count)){
			if( count>0 ){
				dm::scada::CCumulant cumulant;
				for( dm::uint16 i=0;i<count;++i ){
					if( m_rxFrame.getData_cumulant(i,cumulant) ){
						if( int(start+i)<m_offset_c || int(start+i)>=m_offset_c+m_size_c ){
							if( !logged ){
								log().info(THISMODULE "超出范围(%d,%d)的累计量%d",m_offset_c,m_size_c+m_offset_c,start+i);
								logged = true;
							}
							continue;
						}
						updateCumulant( start+i,cumulant.getRaw());
					}else{
						log().warnning(THISMODULE "获取累计量信息失败%d",i);
						break;
					}
				}

				m_callIndex += count;
				log().debug(THISMODULE "召唤下一组累计量%d",m_callIndex);
			}else{
				log().debug(THISMODULE "召唤累计量完成");
				endTask_call(ts,rts,Success);
			}
		}

		break;
	case CFrameDm::Fun_Msg:
		if( m_rxFrame.getMsg(msg) ){
			switch(msg.getType()){
			case dm::msg::Msg_RemoteCtl:
				if( msg.getRemoteCtl().index>=m_offset_r && msg.getRemoteCtl().index<m_offset_r+m_size_r ){
					msg.getRemoteCtl().index = getRemoteControlIndex(msg.getRemoteCtl().index);
					m_msgAgent.sendMsg(msg);
				}else{
					log().info(THISMODULE "超出范围(%d,%d)的远控%d",m_offset_r,m_size_r+m_offset_r,msg.getRemoteCtl().index);
				}

				break;
			case dm::msg::Msg_Get:
			case dm::msg::Msg_Set:
			case dm::msg::Msg_Update:
				if( msg.getPara().index>=m_offset_p && msg.getPara().index<m_offset_p+m_size_p ){
					msg.getPara().index = getParameterIndex(msg.getPara().index);
					m_msgAgent.sendMsg(msg);
				}else{
					log().info(THISMODULE "超出范围(%d,%d)的参数%d",m_offset_p,m_size_p+m_offset_p,msg.getPara().index);
				}

				break;
			default:
				break;
			}
		}

		break;
	case CFrameDm::Fun_Report_Event:
		if( m_rxFrame.getReport_event(count) ){
			dm::scada::CEvent e;
			for( dm::uint16 i=0;i<count;++i ){
				m_rxFrame.getReport_event(i,e);
				if( e.type==e.Status ){
					if( e.idx<m_offset_s || e.idx>=m_offset_s+m_size_s ){
						if( !logged ){
							log().warnning(THISMODULE "状态量%d事件超出范围(%d,%d)",e.idx,m_offset_s,m_size_s+m_offset_s);
							logged = true;
						}
						continue;
					}

					if( e.ts>ts ){
						log().info(THISMODULE "事件时标异常 状态量%d,值%d,%d.%03d(%s) 当前%d.%03d(%s)",
								e.idx,e.value.status,e.ts.seconds(),e.ts.mseconds(),dm::CDateTime(e.ts).toString().c_str(),
								ts.seconds(),ts.mseconds(),dm::CDateTime(ts).toString().c_str());
						updateStatus( e.idx,dm::scada::CStatus(e.value.status,e.value.status),dm::scada::BySyncAdjust,ts);
					}else
						updateStatus( e.idx,dm::scada::CStatus(e.value.status,e.value.status),dm::scada::BySync,e.ts);
				}else if( e.type==e.Discrete ){
					if( e.idx<m_offset_d || e.idx>=m_offset_d+m_size_d ){
						if( !logged ){
							log().warnning(THISMODULE "离散量%d事件超出范围(%d,%d)",e.idx,m_offset_d,m_size_d+m_offset_d);
							logged = true;
						}
						continue;
					}

					if( e.ts>ts ){
						log().info(THISMODULE "事件时标异常 离散量%d,值%d,%d.%03d(%s) 当前%d.%03d(%s)",
								e.idx,e.value.status,e.ts.seconds(),e.ts.mseconds(),dm::CDateTime(e.ts).toString().c_str(),
								ts.seconds(),ts.mseconds(),dm::CDateTime(ts).toString().c_str());
						updateDiscrete( e.idx,dm::scada::CDiscrete(e.value.discrete,e.value.discrete),dm::scada::BySyncAdjust,ts);
					}else
						updateDiscrete( e.idx,dm::scada::CDiscrete(e.value.discrete,e.value.discrete),dm::scada::BySync,e.ts);
				}else{
					log().warnning(THISMODULE "未知事件类型%d",e.type);
				}
			}
		}
		break;
	case CFrameDm::Fun_Report_TimedMeasure:
		if( m_rxFrame.getReport_timedMeasure(count) ){
			dm::scada::CTimedMeasure m;
			for( dm::uint16 i=0;i<count;++i ){
				m_rxFrame.getReport_timedMeasure(i,m);
				if( m.getIndex()<m_offset_m || m.getIndex()>=m_offset_m+m_size_m ){
					if( !logged ){
						log().warnning(THISMODULE "时标测量量%d超出范围(%d,%d)",m.getIndex(),m_offset_m,m_size_m+m_offset_m);
						logged = true;
					}
					continue;
				}

				if( m.getTimeStamp()>ts ){
					log().debug(THISMODULE "时标测量量异常 %d,值%f,%d.%03d(%s) 当前%d.%03d(%s)",
							m.getIndex(),m.getValue(),m.getTimeStamp().seconds(),m.getTimeStamp().mseconds(),
							dm::CDateTime(m.getTimeStamp()).toString().c_str(),ts.seconds(),ts.mseconds(),dm::CDateTime(ts).toString().c_str());
					updateMeasure(m.getIndex(),m.getValue(),dm::scada::BySyncAdjust,ts);
				}else
					updateMeasure(m.getIndex(),m.getValue(),dm::scada::BySync,m.getTimeStamp());
			}

			log().debug(THISMODULE "收到时标测量量%d个",count);
		}
		break;
	case CFrameDm::Fun_Report_TimedCumulant:
		if( m_rxFrame.getReport_timedCumulant(count) ){
			dm::scada::CTimedCumulant c;
			for( dm::uint16 i=0;i<count;++i ){
				m_rxFrame.getReport_timedCumulant(i,c);
				if( c.getIndex()<m_offset_c || c.getIndex()>=m_offset_c+m_size_c ){
					if( !logged ){
						log().warnning(THISMODULE "时标累计量%d超出范围(%d,%d)",c.getIndex(),m_offset_c,m_size_c+m_offset_c);
						logged = true;
					}
					continue;
				}

				if( c.getTimeStamp()>ts ){
					log().debug(THISMODULE "时标累计量异常 %d,值%ull,%d.%03d(%s) 当前%d.%03d(%s)",
							c.getIndex(),c.getRaw(),c.getTimeStamp().seconds(),c.getTimeStamp().mseconds(),
							dm::CDateTime(c.getTimeStamp()).toString().c_str(),ts.seconds(),ts.mseconds(),dm::CDateTime(ts).toString().c_str());
					updateCumulant(c.getIndex(),c.getRaw(),dm::scada::BySyncAdjust,ts);
				}else
					updateCumulant(c.getIndex(),c.getRaw(),dm::scada::BySync,c.getTimeStamp());
			}

			log().debug(THISMODULE "收到时标累计量%d个",count);
		}
		break;

	case CFrameDm::Fun_Clock:
		if( m_rxFrame.getClock(st) ){
			if( m_acceptClock ){
				dm::CDateTime dt(dm::CTimeStamp(st,0));
				if( dm::CDateTime::setRtc(dt) ){
					log().info(THISMODULE "接受对时 %s 成功",dt.toString().c_str());
				}else{
					log().info(THISMODULE "接受对时 %s 失败",dt.toString().c_str());
				}
			}else{
				log().warnning(THISMODULE "不接受对时");
			}
		}
		break;

	default:
		break;
	}

	return Action_Nothing;
}

CMasterDm::EAction CMasterDm::taskStart_call( const ts_t& /*ts*/,const rts_t& rts ){
	EAction act = checkWait(rts);
	if( act!=Action_Nothing )
		return act;

	dm::os::msg::CMsgInfo msg;
	msg.setRequest_call(0,false);

	m_txFrame.setMsg(msg);

	m_taskCall = Started;
	m_callStep = (ECallStep)m_callGroup;
	m_callIndex = m_offset_s;

	wait(rts);

	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::taskDo_call( const ts_t& ts,const rts_t& rts ){
	EAction act = checkWait(rts);
	if( act!=Action_Nothing )
		return act;

	switch( m_callStep ){
	case CSStatus:
		if( m_callIndex>=m_offset_s+m_size_s ){
			m_callStep = CSDiscrete;
			m_callIndex = m_offset_d;
			return Action_Nothing;
		}

		m_txFrame.setRead_status(m_callIndex,1024);
		break;
	case CSDiscrete:
		if( m_callIndex>=m_offset_d+m_size_d ){
			m_callStep = CSMeasure;
			m_callIndex = m_offset_m;
			return Action_Nothing;
		}
		m_txFrame.setRead_discrete(m_callIndex,1024);
		break;
	case CSMeasure:
		if( m_callIndex>=m_offset_m+m_size_m ){
			m_callStep = CSCumulant;
			m_callIndex = m_offset_c;
			return Action_Nothing;
		}
		m_txFrame.setRead_measure(m_callIndex,1024);
		break;
	case CSCumulant:
		if( m_callIndex>=m_offset_s+m_size_s ){
			endTask_call(ts,rts,Success);
			return Action_Nothing;
		}

		m_txFrame.setRead_cumulant(m_callIndex,1024);
		break;
	default:
		endTask_call(ts,rts,Success);
		return Action_Nothing;
	}

	m_tsCall = rts;

	wait(rts);

	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::task_none( const ts_t& ts,const rts_t& rts ){
	EAction act = dm::os::protocol::CProtocolMaster::task_none(ts,rts);
	if( act!=Action_Nothing )
		return act;

	act = checkWait(rts);
	if( act!=Action_Nothing )
		return act;

	if( m_clockInterval>0 && m_lastClock.isTimeout_sec(m_clockInterval) ){
		m_lastClock = rts;

		m_txFrame.setClock( ts.m_s );
		wait(rts);
		return Action_SendAndReTime;
	}

	m_txFrame.setTest();

	if( m_tsCall.isTimeout_sec(m_callInterval) ){
		setTask_call(ts,rts,0);
	}

	wait(rts);
	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::onMsgRequest_syncClock( dm::os::msg::CMsgInfo& /*msg*/,const ts_t& ts,const rts_t& /*rts*/ ){
	m_txFrame.setClock(ts.seconds());
	enableRequestMsgCheck(false);
	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::onMsgRequest_call( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	m_txFrame.setMsg(msg);
	enableRequestMsgCheck(false);
	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::onMsgRequest_rmtCtl( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getRemoteCtl().index = getLocalRemoteControlIndex(msg.getRemoteCtl().index);
	if( msg.getRemoteCtl().index<m_offset_r || msg.getRemoteCtl().index>=m_offset_r+m_size_r ){
		return Action_Nothing;
	}else{
		m_txFrame.setMsg(msg);
		enableRequestMsgCheck(false);
		return Action_SendAndReTime;
	}
}

CMasterDm::EAction CMasterDm::onMsgRequest_set( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getParaData().index = getLocalParamterIndex(msg.getParaData().index);

	if( msg.getParaData().index<m_offset_p || msg.getParaData().index>=m_offset_p+m_size_p )
		return Action_Nothing;
	else{
		m_txFrame.setMsg(msg);
		enableRequestMsgCheck(false);
		return Action_SendAndReTime;
	}
}

CMasterDm::EAction CMasterDm::onMsgRequest_get( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getParaData().index = getLocalParamterIndex(msg.getParaData().index);

	if( msg.getParaData().index<m_offset_p || msg.getParaData().index>=m_offset_p+m_size_p )
		return Action_Nothing;
	else{
		m_txFrame.setMsg(msg);
		enableRequestMsgCheck(false);
		return Action_SendAndReTime;
	}
}

CMasterDm::EAction CMasterDm::onMsgRequest_syncData( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	m_txFrame.setMsg(msg);
	enableRequestMsgCheck(false);
	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::onMsgRequest_remoteReset( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	m_txFrame.setMsg(msg);
	enableRequestMsgCheck(false);
	return Action_SendAndReTime;
}

CMasterDm::EAction CMasterDm::onMsgAnswer_update( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getParaData().index = getLocalParamterIndex(msg.getParaData().index);

	m_txFrame.setMsg(msg);
	enableRequestMsgCheck(false);
	return Action_SendAndReTime;
}
